﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace Isuka.Reflection
{
    class AnonymousTypeHelper
    {
        readonly object target;
        readonly Type targetType;
        readonly PropertyInfo[] properties;

        public AnonymousTypeHelper(object obj)
        {
            Contract.Requires<ArgumentNullException>(obj != null, "obj");

            target = obj;
            targetType = obj.GetType();
            properties = targetType.GetProperties();
        }

        public object[] GetAllValues()
        {
            Contract.Ensures(Contract.Result<object[]>() != null);
            return properties.Select(x => x.GetValue(target, null)).ToArray();
        }

        public object GetValue(PropertyInfo info)
        {
            Contract.Requires<ArgumentNullException>(info != null, "info");
            return info.GetValue(target, null);
        }

        public object GetValue(string name)
        {
            Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(name));
            return
                properties
                    .Where(x => x.Name == name)
                    .Select(x => x.GetValue(target, null))
                    .FirstOrDefault()
                    ;
        }

        public PropertyInfo[] Properties
        {
            get
            {
                Contract.Ensures(Contract.Result<PropertyInfo[]>() != null);
                return properties;
            }
        }

        #region ObjectInvariant

        [ContractInvariantMethod]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        private void ObjectInvariant()
        {
            Contract.Invariant(target != null);
            Contract.Invariant(targetType != null);
            Contract.Invariant(properties != null);
        }

        #endregion

    }
}
